package com.ruoyi.api.daoru;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * 通用导入工具类，封装 Excel 导入的公共逻辑
 */
@Setter
@Getter
@Component
public class ImportUtils {
    private static final Logger log = LoggerFactory.getLogger(ImportUtils.class);
    // 默认最大导入数量
    private static final int DEFAULT_MAX_IMPORT_SIZE = 500;
    private int maxImportSize = DEFAULT_MAX_IMPORT_SIZE;

    /**
     * 通用导入方法
     * @param file 上传的 Excel 文件
     * @param clazz 实体类类型
     * @param validator 数据校验函数
     * @param saver 数据保存函数
     * @param <T> 实体类类型
     * @return 导入结果
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> ImportResult importData(MultipartFile file, Class<T> clazz,
                                       BiFunction<T, Integer, List<String>> validator,
                                       Function<List<T>, Void> saver) {
        List<T> dataList = new ArrayList<>();
        List<ImportError> errorList = new ArrayList<>();
        AtomicBoolean hasError = new AtomicBoolean(false); // 用于标记是否发生了致命错误

        try (InputStream inputStream = file.getInputStream()) {
            // 读取 Excel 并校验数据
            EasyExcel.read(inputStream, clazz, new AnalysisEventListener<T>() {
                @Override
                public void invoke(T entity, AnalysisContext context) {
                    // 如果已经有致命错误，直接跳过后续处理
                    if (hasError.get()) {
                        return;
                    }

                    int rowIndex = context.readRowHolder().getRowIndex() + 1;
                    log.debug("处理行号: {}, 当前已导入数据量: {}", rowIndex, dataList.size());

                    // 检查是否超过最大导入数量
                    if (dataList.size() >= maxImportSize) {
                        log.error("超过最大导入数量限制: {}", maxImportSize);
                        hasError.set(true); // 设置致命错误标记
                        throw new ExcelAnalysisStopException("导入失败，数据行数超过最大限制" + maxImportSize + "条");
                    }

                    List<String> errors = validator.apply(entity, rowIndex);
                    if (!errors.isEmpty()) {
                        errors.forEach(msg -> {
                            log.warn("行号 {} 校验失败: {}", rowIndex, msg);
                            errorList.add(new ImportError(rowIndex, msg));
                        });
                    } else {
                        dataList.add(entity);
                        log.debug("行号 {} 数据有效，已添加到导入列表", rowIndex);
                    }
                }

                @Override
                public void onException(Exception exception, AnalysisContext context) {
                    if (exception instanceof ExcelAnalysisStopException) {
                        log.error("导入终止: {}", exception.getMessage());
                        hasError.set(true); // 设置致命错误标记
                        throw (ExcelAnalysisStopException) exception;
                    } else {
                        int rowIndex = context.readRowHolder() != null ?
                                context.readRowHolder().getRowIndex() + 1 : 0;
                        log.error("行号 {} 解析异常: {}", rowIndex, exception.getMessage(), exception);
                        errorList.add(new ImportError(rowIndex, "解析错误:" + exception.getMessage()));
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    log.info("导入解析完成，共处理 {} 行数据", dataList.size() + errorList.size());
                }
            }).sheet().doRead();

            // 检查是否有致命错误
            if (hasError.get()) {
                log.error("检测到致命错误，终止导入流程");
                return ImportResult.failure("导入失败，数据行数超过最大限制" + maxImportSize + "条");
            }

            // 检查普通校验错误
            if (!errorList.isEmpty()) {
                log.warn("导入失败，存在 {} 条校验错误", errorList.size());
                return ImportResult.failureWithErrors(
                        "导入失败，共" + errorList.size() + "条错误",
                        errorList
                );
            }

            // 保存数据
            if (!dataList.isEmpty()) {
                log.info("开始保存 {} 条有效数据", dataList.size());
                saver.apply(dataList);
                log.info("数据保存成功");
            }

            log.info("导入成功，共 {} 条数据", dataList.size());
            return ImportResult.success("导入成功，共" + dataList.size() + "条数据");
        } catch (ExcelAnalysisStopException e) {
            // 捕获异常但不执行保存操作
            log.error("导入失败: {}", e.getMessage());
            return ImportResult.failure(e.getMessage());
        } catch (Exception e) {
            log.error("导入过程发生异常", e);
            return ImportResult.failure("导入失败:" + e.getMessage());
        }
    }
}
